package com.cwj.mylibrary;

public class IprangeUtils {

    /**
     * 判断给定IP地址是否在指定网段中
     * network  eg：172.30.29.0/25
     * ip       eg: 172.30.29.129
     *
     */
    public static Boolean isContains(String network, String ip) {
        String[] networkArr = network.split("/");
        String networkBin = transIpToBrinary(networkArr[0]);
        String ipBin = transIpToBrinary(ip);

        int mask = Integer.parseInt(networkArr[1]);
        //如果掩码长度不在1-32之间，就直接比较俩地址吧
        if (mask < 0 || mask >= 32)
            return ip.equals(network);

        //这一步实际是想求ip地址的大段，没想好怎么算，就先这样算了
        int targetMask = mask / 8;
        int newMask = targetMask * 8;
        //根据network地址求出网段中最大的主机地址
        // （这里包含广播地址，既然是匹配IP是否在此网段中，就未对广播地址及网关地址清除）
        StringBuilder networkMaxHostBuilder = new StringBuilder();
        networkMaxHostBuilder.append(networkBin, 0, mask);  //取网络位
        for (int i = mask; i < 32; i++) {
            networkMaxHostBuilder.append("1");  // 主机位补上1，这就拼成了此网段中最大主机地址
        }

        //截取主机位转换为十进制，进行比较
        int networkMinHost = Integer.parseInt(networkBin.substring(newMask, 32), 2);
        int networkMaxHost = Integer.parseInt(networkMaxHostBuilder.substring(newMask, 32), 2);
        int ipBinary = Integer.parseInt(ipBin.substring(newMask, 32), 2);
        //网络位要相等
        if (networkBin.substring(0, newMask).equals(ipBin.substring(0, newMask))) {
            //且必须在主机地址中
            return ipBinary >= networkMinHost && ipBinary <= networkMaxHost;
        }
        return false;
    }

    /**
     * 转换ip地址
     */
    private static String transIpToBrinary(String ip) {
        String[] ipArr = ip.split("\\.");
        String net;
        StringBuilder netBuilder = new StringBuilder();
        for (String s : ipArr) {
            net = doTransToBinary(s);
            netBuilder.append(net);
        }
        return netBuilder.toString();
    }

    /**
     * 转换十进制为二进制
     */
    private static String doTransToBinary(String ip) {
        int numInt = Integer.parseInt(ip);
        StringBuilder binaryBuilder = new StringBuilder();
        for (int i = 7; i >= 0; i--) {
            int binary = numInt >>> i & 1;
            binaryBuilder.append(binary);
        }
        return binaryBuilder.toString();
    }
}
